package services

import (
	"context"
	"github.com/golang/protobuf/ptypes/empty"
	"github.com/golang/protobuf/ptypes/wrappers"
	"sort"

	context2 "kop/framework/context"
	"kop/framework/errors"
	"kop/modules/award/models"
	"kop/modules/battle/models/battle"
	"kop/modules/configuration/configuration/bufftype"
	itemConsts "kop/modules/item/consts"
	"kop/modules/treasure/configuration/buff"
	"kop/modules/treasure/configuration/point"
	"kop/modules/treasure/consts"
	"kop/pb"

	captainC "kop/modules/captain/client"
	moneyC "kop/modules/money/client"
	questC "kop/modules/quest/client"
	roleC "kop/modules/role/client"
	treasureC "kop/modules/treasure/client"
	cellM "kop/modules/treasure/models/cell"
)

type TreasureService struct {
	context2.Context
}

// 寻宝
func (s *TreasureService) Main(ctx context.Context, _ *empty.Empty) (*pb.TreasureMainReply, error) {

	var reply pb.TreasureMainReply

	var roleID = s.GetRoleID(ctx)
	var treasure = treasureC.GetTreasure(roleID)

	reply.PlayNum = treasure.PlayNum
	reply.RefreshSec = treasure.RefreshSec

	if treasure.MapID == 0 {
		treasure = nil
	}

	reply.Treasure = treasure
	reply.Grades = treasureC.GetGrades(roleID)

	return &reply, nil
}

// 进入地图
// 上一次正常结束这次初始化数据
func (s *TreasureService) In(ctx context.Context, req *wrappers.Int32Value) (*pb.TreasureInReply, error) {

	var reply pb.TreasureInReply

	var roleID = s.GetRoleID(ctx)
	var treasure = treasureC.GetTreasure(roleID)

	if treasure.MapID == 0 {

		var err error
		treasure, err = treasureC.Init(roleID, req.Value)
		if err != nil {
			return &reply, err
		}

		// 日常任务
		questC.DailyQuestTreasure(roleID)
	}

	reply.PlayNum = treasure.PlayNum
	reply.Treasure = treasure
	return &reply, nil
}

// 探索未知区域
func (s *TreasureService) Explore(ctx context.Context, req *pb.XY) (*pb.TreasureExploreReply, error) {

	var reply pb.TreasureExploreReply

	if req.X < 1 || req.X > consts.X || req.Y < 1 || req.Y > consts.Y {
		return &reply, errors.ParamError
	}

	var roleID = s.GetRoleID(ctx)
	var err error

	reply.Treasure, err = treasureC.Explore(roleID, req.X, req.Y)
	if err != nil {
		return &reply, err
	}

	reply.Money, err = moneyC.SubCoin(ctx, reply.Treasure.CostCoin)
	return &reply, err
}

func (s *TreasureService) Box(ctx context.Context, req *pb.XY) (*pb.TreasureBoxReply, error) {

	var reply pb.TreasureBoxReply

	var roleID = s.GetRoleID(ctx)

	var role = roleC.GetRole(roleID)

	reply.Treasure = treasureC.Box(roleID, req.X, req.Y)

	var cell = cellM.Cells(reply.Treasure.Cells).GetCell(req.X, req.Y)

	reply.Award = models.RandAward(role, cell.AwardID)
	return &reply, models.SendAward(role, reply.Award)
}

// 拦截船战
func (s *TreasureService) NpcBattle(ctx context.Context, req *pb.XY) (*pb.TreasureBattleReply, error) {

	var reply pb.TreasureBattleReply

	var roleID = s.GetRoleID(ctx)
	var treasure = treasureC.GetTreasure(roleID)

	if treasure.MapID < 1 {
		return &reply, errors.ParamError
	}

	var cell = cellM.Cells(treasure.Cells).GetCell(req.X, req.Y)
	if cell.State != pb.TCellState_Open || cell.Type != pb.TCellType_Npc {
		return &reply, errors.New("目标错误")
	}

	reply.Fighter1 = captainC.GetCaptainsByReady(roleID)
	reply.Fighter2 = []*pb.Captain{cell.Npc}

	sort.Sort(Captains(reply.Fighter1))

	s.setBuff(reply.Fighter1, treasure.Buff1)
	s.setBuff(reply.Fighter1, treasure.Buff2)
	s.setBuff(reply.Fighter1, treasure.Buff3)

	var err error
	reply.BattleResult, err = battle.Battle(reply.Fighter1, reply.Fighter2)
	if err != nil {
		return &reply, err
	}

	if reply.BattleResult.Win {

		var role = roleC.GetRole(roleID)
		reply.Award = models.RandAward(role, cell.AwardID)

		reply.Treasure = treasureC.NPCWin(roleID, req.X, req.Y)
		return &reply, models.SendAward(role, reply.Award)
	} else {

		reply.Treasure = treasure
		return &reply, nil
	}
}

// Boss战
func (s *TreasureService) BossBattle(ctx context.Context, _ *empty.Empty) (*pb.TreasureBattleReply, error) {

	var reply pb.TreasureBattleReply

	var roleID = s.GetRoleID(ctx)
	var treasure = treasureC.GetTreasure(roleID)

	if treasure.MapID < 1 {
		return &reply, errors.ParamError
	}

	var cell *pb.Cell
	for _, c := range treasure.Cells {
		if c.Type == pb.TCellType_Boss && c.State == pb.TCellState_Open {
			cell = c
		}
	}

	if cell == nil {
		return &reply, errors.New("BOSS还没找到")
	}

	reply.Fighter1 = captainC.GetCaptainsByReady(roleID)
	reply.Fighter2 = []*pb.Captain{cell.Npc}

	sort.Sort(Captains(reply.Fighter1))

	s.setBuff(reply.Fighter1, treasure.Buff1)
	s.setBuff(reply.Fighter1, treasure.Buff2)
	s.setBuff(reply.Fighter1, treasure.Buff3)

	var err error
	reply.BattleResult, err = battle.Battle(reply.Fighter1, reply.Fighter2)
	if err != nil {
		return &reply, err
	}

	if reply.BattleResult.Win {

		var role = roleC.GetRole(roleID)
		reply.Award = models.RandAward(role, cell.AwardID)

		treasure = treasureC.BossWin(roleID, cell.X, cell.Y)

		if err = models.SendAward(role, reply.Award); err != nil {
			return &reply, err
		}
	}

	reply.Treasure = treasure
	return &reply, nil
}

func (s *TreasureService) Buff(ctx context.Context, req *wrappers.Int32Value) (*pb.Treasure, error) {

	if req.Value < 0 || req.Value > 2 {
		return &pb.Treasure{}, errors.ParamError
	}

	var roleID = s.GetRoleID(ctx)
	var treasure = treasureC.GetTreasure(roleID)

	if len(treasure.BuffOptions) == 0 {
		return &pb.Treasure{}, errors.ParamError
	}

	return treasure, treasureC.Buff(treasure, req.Value)
}

// 完成寻宝
func (s *TreasureService) Finish(ctx context.Context, _ *empty.Empty) (*pb.TreasureFinishReply, error) {

	var reply pb.TreasureFinishReply

	var roleID = s.GetRoleID(ctx)
	var treasure = treasureC.GetTreasure(roleID)

	if treasure.MapID < 1 {
		return &reply, errors.ParamError
	}

	var cell *pb.Cell
	for _, c := range treasure.Cells {
		if c.Type == pb.TCellType_Cup {
			cell = c
		}
	}

	var conf, err = point.GetByPoint(treasure.Point1 + treasure.Point2 + treasure.Point3 + treasure.Point4)
	if err != nil {
		return &reply, err
	}

	var addRate = conf.AwardRate // 奖励加成
	if treasure.Buff1 == 8 || treasure.Buff2 == 8 || treasure.Buff3 == 8 {
		// buff奖励加成
		var buffConf, _ = buff.GetByBuffID(8)
		addRate += buffConf.Value
	}

	var res = treasureC.Finish(treasure)
	reply.RefreshSec = res.Treasure.RefreshSec

	if cell == nil {
		// 未找到宝藏 直接退出副本
		return &reply, nil
	}

	var role = roleC.GetRole(roleID)

	reply.Grade = res.Grade
	var award = models.RandAward(role, cell.AwardID)

	award.Coin += int64(float64(award.Coin) * addRate)
	for _, v := range award.AwardItems {
		if v.RawItem.ItemID == itemConsts.RoleExp {
			v.RawItem.Number += int32(float64(v.RawItem.Number) * addRate)
		}
	}

	reply.Award = award
	return &reply, models.SendAward(role, reply.Award)
}

const SS = 5

// 一键过本
func (s *TreasureService) OneKey(ctx context.Context, req *wrappers.Int32Value) (*pb.TreasureOneKeyReply, error) {

	var reply pb.TreasureOneKeyReply

	var roleID = s.GetRoleID(ctx)
	var treasurePoint = treasureC.GetPoint(roleID, req.Value)

	if treasurePoint.Grade < SS {
		return &reply, errors.New("不是SS级评价不能一键过本")
	}

	var conf, err = point.GetByGrade(treasurePoint.Grade)
	if err != nil {
		return &reply, err
	}

	var treasure = treasureC.GetTreasure(roleID)

	if treasure.PlayNum < 1 {
		return &reply, errors.ParamError
	}

	*treasure = pb.Treasure{
		RoleID:  roleID,
		PlayNum: treasure.PlayNum - 1,
		MapID:   0,
		Cells:   []*pb.Cell{},
		//Captains:    []*pb.Captain{},
		BuffOptions: []int32{},
	}

	treasureC.Save(treasure)

	var role = roleC.GetRole(roleID)
	var award = models.RandAward(role, treasurePoint.AwardID)

	award.Coin += int64(float64(award.Coin) * conf.AwardRate)
	for _, v := range award.AwardItems {
		if v.RawItem.ItemID == itemConsts.RoleExp {
			v.RawItem.Number += int32(float64(v.RawItem.Number) * conf.AwardRate)
		}
	}

	reply.PlayNum = treasure.PlayNum
	reply.RefreshSec = treasure.RefreshSec
	reply.Award = award
	return &reply, models.SendAward(role, reply.Award)
}

func (s *TreasureService) AddNum(ctx context.Context, req *empty.Empty) (*wrappers.Int32Value, error) {

	return treasureC.TreasureService.AddNum(ctx, req)
}

func (s *TreasureService) setBuff(captains []*pb.Captain, buffID int32) {

	if buffID > 0 {
		var buffConf, _ = buff.GetByBuffID(buffID)

		if buffConf.BuffType == bufftype.INT || buffConf.BuffType == bufftype.COR {
			// 增加船长属性值
			for _, captain := range captains {
				if captain.Camp == buffConf.Camp {
					switch buffConf.BuffType {
					case bufftype.INT:
						captain.Attribute.INT = int32(float64(captain.Attribute.INT) * (1 + buffConf.Value))
					case bufftype.COR:
						captain.Attribute.COR = int32(float64(captain.Attribute.COR) * (1 + buffConf.Value))
					}
				}
			}
		}
	}
}
